using System;
using System.Diagnostics;

using org.fourzoas.noise.module;

namespace org.fourzoas.noise.module {
  /// <summary>
  /// Noise module that outputs three-dimensional "billowy" noise.
  /// </summary>
  /// <remarks>
  /// <img src="file://C:/temp/noise/noise/doc/html/modulebillow.png"/>
  /// <para>
  /// This noise module generates "billowy" noise suitable for clouds and rocks.
  /// </para>
  /// <para>
  /// This noise module is nearly identical to <see cref="Perlin"/> except this noise module
  /// modifies each octave with an absolute-value function.  See the documentation for <see cref="Perlin"/>
  /// for more information.
  /// </para>
  /// </remarks>
  /// <seealso cref="Perlin"/>
  public class Billow : GeneratorModule {
    #region Billow Constants
    /// <summary>
    /// Default frequency for the <see cref="Billow"/> noise module.
    /// </summary>
    public  const double DEFAULT_BILLOW_FREQUENCY = 1.0;
    /// <summary>
    /// Default lacunarity for the <see cref="Billow"/> noise module.
    /// </summary>
    public const double DEFAULT_BILLOW_LACUNARITY = 2.0;
    /// <summary>
    /// Default number of octaves for the <see cref="Billow"/> noise module.
    /// </summary>
    public const int DEFAULT_BILLOW_OCTAVE_COUNT = 6;
    /// <summary>
    /// Default persistence value for the <see cref="Billow"/> noise module.
    /// </summary>
    public const double DEFAULT_BILLOW_PERSISTENCE = 0.5;
    /// <summary>
    /// Default noise quality for the <see cref="Billow"/> noise module.
    /// </summary>
    public const NoiseQuality DEFAULT_BILLOW_QUALITY = NoiseQuality.QUALITY_STD;
    /// <summary>
    /// Default noise seed for the <see cref="Billow"/> noise module.
    /// </summary>
    public const int DEFAULT_BILLOW_SEED = 0;
    /// <summary>
    /// Maximum number of octaves for the <see cref="Billow"/> noise module.
    /// </summary>
    public int BILLOW_MAX_OCTAVE = 60;
    #endregion
    /// <summary>
    /// Default constructor.
    /// </summary>
    /// <remarks>
    /// <list type="bullet">
    /// <item>The default frequency is set to <see cref="DEFAULT_BILLOW_FREQUENCY"/>.</item>
    /// <item>The default lacunarity is set to <see cref="DEFAULT_BILLOW_LACUNARITY"/>.</item>
    /// <item>The default number of octaves is set to <see cref="DEFAULT_BILLOW_OCTAVE_COUNT"/>.</item>
    /// <item>The default persistence value is set to <see cref="DEFAULT_BILLOW_PERSISTENCE"/>.</item>
    /// <item>The default seed value is set to <see cref="DEFAULT_BILLOW_SEED"/>.</item>
    /// </list>
    /// </remarks>
    public Billow()
      : base(0) {
      m_frequency = DEFAULT_BILLOW_FREQUENCY;
      m_lacunarity = DEFAULT_BILLOW_LACUNARITY;
      m_noiseQuality = DEFAULT_BILLOW_QUALITY;
      m_octaveCount = DEFAULT_BILLOW_OCTAVE_COUNT;
      m_persistence = DEFAULT_BILLOW_PERSISTENCE;
      m_seed = DEFAULT_BILLOW_SEED;
    }

    /// <summary>
    /// Returns the number of source modules this noise module requires.
    /// </summary>
    /// <returns>0</returns>
    public override int GetSourceModuleCount() {
      return 0;
    }

    /// <summary>
    /// Generates an output value given the coordinates of the specified input value.
    /// </summary>
    /// <param name="x">The <em>x</em> coordinate of the input value.</param>
    /// <param name="y">The <em>y</em> coordinate of the input value.</param>
    /// <param name="z">The <em>z</em> coordinate of the input value.</param>
    /// <returns>The output value.</returns>
    public override double GetValue(double x, double y, double z) {
      double value = 0.0;
      double signal = 0.0;
      double curPersistence = 1.0;
      double nx, ny, nz;
      long seed;
      x *= m_frequency;
      y *= m_frequency;
      z *= m_frequency;
      for (int curOctave = 0; curOctave < m_octaveCount; curOctave++) {
        // Make sure these doubling-point values have the same range as a 64-bit integer so that we
        // can pass them to the coherent-noise functions.
        nx = Globals.MakeInt64Range(x);
        ny = Globals.MakeInt64Range(y);
        nz = Globals.MakeInt64Range(z);

        // Get the coherent-noise value from the input value and add it to the final result.
        seed = (long)(((ulong)(m_seed + curOctave)) & 0xffffffffffffffffL);
        signal = Globals.GradientCoherentNoise3D(nx, ny, nz, seed, m_noiseQuality);
        signal = 2.0 * Math.Abs(signal) - 1.0;
        value += signal * curPersistence;

        // Prepare the next octave.
        x *= m_lacunarity;
        y *= m_lacunarity;
        z *= m_lacunarity;
        curPersistence *= m_persistence;
      }
      value += 0.5;
      return value;
    }

    /// <summary>
    /// Sets or returns the frequency of the first octave.
    /// </summary>
    public double Frequency {
      get { return m_frequency; }
      set { m_frequency = value; }
    }

    /// <summary>
    /// Sets or returns the lacunarity of the billowy noise.
    /// </summary>
    /// <remarks>The lacunarity is the frequency multiplier between successive octaves.</remarks>
    public double Lacunarity {
      get { return m_lacunarity; }
      set { m_lacunarity = value; }
    }

    /// <summary>
    /// Sets or returns the quality of the billowy noise.
    /// </summary>
    /// <remarks>See <see cref="NoiseQuality"/> for the definitions of the various coherent-noise qualities.</remarks>
    public NoiseQuality NoiseQuality {
      get { return m_noiseQuality; }
      set { m_noiseQuality = value; }
    }

    /// <summary>
    /// Sets or returns the number of octaves that generate the billowy noise.
    /// </summary>
    /// <remarks>The number of octaves controls the amount of detail in the billowy noise.</remarks>
    public int OctaveCount {
      get { return m_octaveCount; }
      set { m_octaveCount = value; }
    }

    /// <summary>
    /// Sets or returns the persistence value of the billowy noise.
    /// </summary>
    /// <remarks>The persistence value controls the roughness of the billowy noise.</remarks>
    public double Persistence {
      get { return m_persistence; }
      set { m_persistence = value; }
    }

    /// <summary>
    /// Sets or returns the seed value used by the billowy-noise function.
    /// </summary>
    public long Seed {
      get { return m_seed; }
      set { m_seed = value; }
    }

    /// <summary>
    /// Frequency of the first octave.
    /// </summary>
    protected double m_frequency;
    /// <summary>
    /// Frequency multiplier between successive octaves.
    /// </summary>
    protected double m_lacunarity;
    /// <summary>
    /// Quality of the billowy noise.
    /// </summary>
    protected NoiseQuality m_noiseQuality;
    /// <summary>
    /// Total number of octaves that generate the billowy noise.
    /// </summary>
    protected int m_octaveCount;
    /// <summary>
    /// Persistence value of the billowy noise.
    /// </summary>
    protected double m_persistence;
    /// <summary>
    /// Seed value used by the billowy-noise function.
    /// </summary>
    protected long m_seed;
  }
}